/**
 * 
 */
package io.dora.remoting;

import io.dora.base.Protocol;
import io.dora.utils.Utils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 服务提供方Netty Server Socket实现
 * 
 * @author zhaohongbo
 *
 */
public class NettyProviderServer extends AbstractProviderServer {
	
	private static final Logger logger = LoggerFactory.getLogger(NettyProviderServer.class);
	
	private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
	
	public NettyProviderServer(Protocol protocol) {
		super(protocol);
	}

	@Override
	public void doServerStart() {
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) 
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChildChannelHandler(this.getServiceMap()));
           serverBootstrap.bind(protocol.getServicePort()).syncUninterruptibly();
           logger.info("Dora netty server {} start on {}", Utils.getIp(), protocol.getServicePort());
        } catch (Exception e) {
        	logger.error("{}", e);
        }
	}

	@Override
	public void doServerStop() {
		bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
	}
	
	/**
	 * 网络事件处理器
	 */
	private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
		
		protected Map<String, Object> serviceMap;
		
		public ChildChannelHandler(Map<String, Object> serviceMap) {
			this.serviceMap = serviceMap;
		}
		
	    @Override
	    protected void initChannel(SocketChannel ch) {
	    	ch.pipeline().addLast(new ObjectEncoder());
	        ch.pipeline().addLast(new ObjectDecoder(1024 * 1024 * 5,ClassResolvers.cacheDisabled(null)));
	        ch.pipeline().addLast(new ProviderHandler(serviceMap));
	    }
	}

}


